menuitem: convert arrow rendering to GtkCssGadget
authorCosimo Cecchi <cosimoc@gnome.org>
Fri, 18 Dec 2015 05:41:40 +0000 (21:41 -0800)
committerCosimo Cecchi <cosimoc@gnome.org>
Sun, 20 Dec 2015 05:21:16 +0000 (21:21 -0800)
This also deprecates the arrow-spacing style property, which can be now
replaced with a simple margin.

gtk/gtkmenuitem.c
gtk/gtkmenuitemprivate.h
gtk/theme/Adwaita/_common.scss
gtk/theme/Adwaita/gtk-contained-dark.css
gtk/theme/Adwaita/gtk-contained.css
gtk/theme/HighContrast/_common.scss
gtk/theme/HighContrast/gtk.css

index 2308eac5197543beb1652fd1daf0efecad4e0851..10a0168963acc013de6fe96d2c0ade68f47278c7 100644 (file)
@@ -27,6 +27,7 @@
 #include <string.h>
 
 #include "gtkaccellabel.h"
+#include "gtkcontainerprivate.h"
 #include "gtkcsscustomgadgetprivate.h"
 #include "gtkmain.h"
 #include "gtkmarshalers.h"
@@ -276,39 +277,71 @@ gtk_menu_item_actionable_interface_init (GtkActionableInterface *iface)
   iface->get_action_target_value = gtk_menu_item_get_action_target_value;
 }
 
+static gboolean
+gtk_menu_item_render_arrow (GtkCssGadget *gadget,
+                            cairo_t      *cr,
+                            int           x,
+                            int           y,
+                            int           width,
+                            int           height,
+                            gpointer      data)
+{
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
+  GtkMenuItemPrivate *priv = menu_item->priv;
+  GtkStyleContext *context;
+  GtkTextDirection direction;
+  gdouble angle;
+
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_save_to_node (context, priv->arrow_node);
+  direction = gtk_widget_get_direction (widget);
+
+  if (direction == GTK_TEXT_DIR_LTR)
+    angle = G_PI / 2;
+  else
+    angle = (3 * G_PI) / 2;
+
+  gtk_render_arrow (context, cr, angle, x, y, width);
+
+  gtk_style_context_restore (context);
+
+  return FALSE;
+}
+
 static void
-get_arrow_size (GtkWidget *widget,
-                GtkWidget *child,
-                gint      *size,
-                gint      *spacing)
+gtk_menu_item_measure_arrow (GtkCssGadget   *gadget,
+                             GtkOrientation  orientation,
+                             int             for_size,
+                             int            *minimum,
+                             int            *natural,
+                             int            *minimum_baseline,
+                             int            *natural_baseline,
+                             gpointer        data)
 {
-  PangoContext     *context;
+  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
+  PangoContext *context;
   PangoFontMetrics *metrics;
-  gfloat            arrow_scaling;
-  gint              arrow_spacing;
-
-  g_assert (size);
+  gfloat arrow_scaling;
+  gint size;
 
   gtk_widget_style_get (widget,
                         "arrow-scaling", &arrow_scaling,
-                        "arrow-spacing", &arrow_spacing,
                         NULL);
 
-  if (spacing != NULL)
-    *spacing = arrow_spacing;
-
-  context = gtk_widget_get_pango_context (child);
+  context = gtk_widget_get_pango_context (widget);
 
   metrics = pango_context_get_metrics (context,
                                        pango_context_get_font_description (context),
                                        pango_context_get_language (context));
 
-  *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
-                         pango_font_metrics_get_descent (metrics)));
+  size = arrow_scaling *
+    (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
+                   pango_font_metrics_get_descent (metrics)));
 
   pango_font_metrics_unref (metrics);
 
-  *size = *size * arrow_scaling;
+  *minimum = *natural = size;
 }
 
 static gboolean
@@ -333,32 +366,7 @@ gtk_menu_item_render (GtkCssGadget *gadget,
 
   if (priv->submenu && !GTK_IS_MENU_BAR (parent))
     {
-      gint arrow_x, arrow_y;
-      gint arrow_size;
-      GtkTextDirection direction;
-      gdouble angle;
-
-      gtk_style_context_save_to_node (context, priv->arrow_node);
-
-      direction = gtk_widget_get_direction (widget);
-      get_arrow_size (widget, child, &arrow_size, NULL);
-
-      if (direction == GTK_TEXT_DIR_LTR)
-        {
-          arrow_x = width - arrow_size;
-          angle = G_PI / 2;
-        }
-      else
-        {
-          arrow_x = 0;
-          angle = (3 * G_PI) / 2;
-        }
-
-      arrow_y = (height - arrow_size) / 2;
-
-      gtk_render_arrow (context, cr, angle, arrow_x, arrow_y, arrow_size);
-
-      gtk_style_context_restore (context);
+      gtk_css_gadget_draw (priv->arrow_gadget, cr);
     }
   else if (!child)
     {
@@ -404,6 +412,7 @@ gtk_menu_item_allocate (GtkCssGadget        *gadget,
   GtkMenuItem *menu_item = GTK_MENU_ITEM (widget);
   GtkMenuItemPrivate *priv = menu_item->priv;
   GtkAllocation child_allocation;
+  GtkAllocation arrow_clip = { 0 };
   GtkTextDirection direction;
   GtkPackDirection child_pack_dir;
   GtkWidget *child;
@@ -445,19 +454,46 @@ gtk_menu_item_allocate (GtkCssGadget        *gadget,
 
       if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
        {
-         gint arrow_spacing, arrow_size;
+          GtkAllocation arrow_alloc;
+
+          gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                             GTK_ORIENTATION_HORIZONTAL,
+                                             -1,
+                                             &arrow_alloc.width, NULL,
+                                             NULL, NULL);
+          gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                             GTK_ORIENTATION_VERTICAL,
+                                             -1,
+                                             &arrow_alloc.height, NULL,
+                                             NULL, NULL);
 
-         get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
+          if (direction == GTK_TEXT_DIR_LTR)
+            {
+              arrow_alloc.x = child_allocation.x +
+                child_allocation.width - arrow_alloc.width;
+            }
+          else
+            {
+              arrow_alloc.x = 0;
+              child_allocation.x += arrow_alloc.width;
+            }
+
+          child_allocation.width -= arrow_alloc.width;
+          arrow_alloc.y = child_allocation.y +
+            (child_allocation.height - arrow_alloc.height) / 2;
 
-         if (direction == GTK_TEXT_DIR_RTL)
-           child_allocation.x += arrow_size + arrow_spacing;
-         child_allocation.width -= arrow_size + arrow_spacing;
+          gtk_css_gadget_allocate (priv->arrow_gadget,
+                                   &arrow_alloc,
+                                   baseline,
+                                   &arrow_clip);
        }
 
-      if (child_allocation.width < 1)
-        child_allocation.width = 1;
+      child_allocation.width = MAX (1, child_allocation.width);
 
       gtk_widget_size_allocate (child, &child_allocation);
+
+      gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip);
+      gdk_rectangle_union (out_clip, &arrow_clip, out_clip);
     }
 
   if (gtk_widget_get_realized (widget))
@@ -529,14 +565,17 @@ gtk_menu_item_real_get_width (GtkWidget *widget,
 
       gtk_widget_get_preferred_width (child, &child_min, &child_nat);
 
-      if ((menu_item->priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
+      if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
        {
-         gint arrow_spacing, arrow_size;
+          gint arrow_size;
 
-         get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
+          gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                             GTK_ORIENTATION_HORIZONTAL,
+                                             -1,
+                                             &arrow_size, NULL,
+                                             NULL, NULL);
 
           min_width += arrow_size;
-          min_width += arrow_spacing;
           nat_width = min_width;
         }
 
@@ -579,14 +618,18 @@ gtk_menu_item_real_get_height (GtkWidget *widget,
   if (child != NULL && gtk_widget_get_visible (child))
     {
       gint child_min, child_nat;
-      gint arrow_size = 0, arrow_spacing = 0;
+      gint arrow_size = 0;
 
       if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator)
-        get_arrow_size (widget, child, &arrow_size, &arrow_spacing);
+        gtk_css_gadget_get_preferred_size (priv->arrow_gadget,
+                                           GTK_ORIENTATION_VERTICAL,
+                                           -1,
+                                           &arrow_size, NULL,
+                                           NULL, NULL);
 
       if (for_size != -1)
         {
-          avail_size -= (arrow_size + arrow_spacing);
+          avail_size -= arrow_size;
           gtk_widget_get_preferred_height_for_width (child,
                                                      avail_size,
                                                      &child_min,
@@ -935,6 +978,14 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
                                                              5,
                                                              GTK_PARAM_READABLE));
 
+  /**
+   * GtkMenuItem:arrow-spacing:
+   *
+   * Spacing between menu item label and submenu arrow.
+   *
+   * Deprecated: 3.20: use the standard margin CSS property on the arrow node;
+   *   the value of this style property is ignored.
+   */
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_int ("arrow-spacing",
                                                              "Arrow Spacing",
@@ -942,7 +993,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass)
                                                              0,
                                                              G_MAXINT,
                                                              10,
-                                                             GTK_PARAM_READABLE));
+                                                             GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
 
   gtk_widget_class_install_style_property (widget_class,
                                            g_param_spec_float ("arrow-scaling",
@@ -1078,6 +1129,7 @@ gtk_menu_item_dispose (GObject *object)
       priv->action = NULL;
     }
 
+  g_clear_object (&priv->arrow_gadget);
   g_clear_object (&priv->gadget);
 
   G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object);
@@ -1214,6 +1266,8 @@ gtk_menu_item_detacher (GtkWidget *widget,
       gtk_css_node_set_parent (priv->arrow_node, NULL);
       priv->arrow_node = NULL;
     }
+
+  g_clear_object (&priv->arrow_gadget);
 }
 
 static void
@@ -1571,6 +1625,14 @@ gtk_menu_item_set_submenu (GtkMenuItem *menu_item,
               gtk_css_node_set_state (priv->arrow_node, gtk_css_node_get_state (widget_node));
               g_signal_connect_object (priv->arrow_node, "style-changed", G_CALLBACK (node_style_changed_cb), menu_item, 0);
 
+              priv->arrow_gadget =
+                gtk_css_custom_gadget_new_for_node (priv->arrow_node,
+                                                    GTK_WIDGET (menu_item),
+                                                    gtk_menu_item_measure_arrow,
+                                                    NULL,
+                                                    gtk_menu_item_render_arrow,
+                                                    NULL, NULL);
+
               update_node_classes (menu_item);
 
               g_object_unref (priv->arrow_node);
index f8069cdd2bec34135abc58b9f785eb914d106c7a..5f3a6da65f900ddcfbd741e4fec3859b1896f5dc 100644 (file)
@@ -42,6 +42,7 @@ struct _GtkMenuItemPrivate
   GtkActionHelper *action_helper;
 
   GtkCssGadget *gadget;
+  GtkCssGadget *arrow_gadget;
   GtkCssNode *arrow_node;
 
   guint submenu_placement      : 1;
index 9be926939a0829ae5f101cd38837254ab47a4d36..d1a965a762323f1ad797c61b533959f37a99b23a 100644 (file)
@@ -1514,8 +1514,14 @@ menu,
       background-color: transparent;
     }
     //submenu indicators
-    & arrow { -gtk-icon-source: -gtk-icontheme('pan-end-symbolic'); }
-    & arrow:dir(rtl) {-gtk-icon-source:-gtk-icontheme('pan-end-symbolic-rtl'); }
+    & arrow {
+      -gtk-icon-source: -gtk-icontheme('pan-end-symbolic');
+      margin-left: 10px;
+    }
+    & arrow:dir(rtl) {
+      -gtk-icon-source:-gtk-icontheme('pan-end-symbolic-rtl');
+      margin-right: 10px;
+    }
   }
   & arrow { // overlow buttons
     @extend %undecorated_button;
index 5431ae093b55892833d8478da6a9c773bb183046..b6b081edf8ceabf64b3466f1c66789d0895075ab 100644 (file)
@@ -2125,10 +2125,12 @@ menu,
       background-color: transparent; }
     menu menuitem arrow,
     .menu menuitem arrow {
-      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); }
+      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic");
+      margin-left: 10px; }
     menu menuitem arrow:dir(rtl),
     .menu menuitem arrow:dir(rtl) {
-      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); }
+      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl");
+      margin-right: 10px; }
   menu arrow,
   .menu arrow {
     border-style: none;
index d419d5b5bc6e47ef9dd01e81017ff4c35781fc46..64eba19cebbe04b78b8944829bba194fcc546f6b 100644 (file)
@@ -2131,10 +2131,12 @@ menu,
       background-color: transparent; }
     menu menuitem arrow,
     .menu menuitem arrow {
-      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic"); }
+      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic");
+      margin-left: 10px; }
     menu menuitem arrow:dir(rtl),
     .menu menuitem arrow:dir(rtl) {
-      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl"); }
+      -gtk-icon-source: -gtk-icontheme("pan-end-symbolic-rtl");
+      margin-right: 10px; }
   menu arrow,
   .menu arrow {
     border-style: none;
index 9e243cb31aed09e16f299e6104db1efe0c015d0e..fa2aeceabd0668c1c7c007891b08f880d3092748 100644 (file)
@@ -1176,6 +1176,12 @@ menu,
 
   menuitem {
     min-width: 40px;
+    & arrow {
+      margin-left: 10px;
+    }
+    & arrow:dir(rtl) {
+      margin-right: 10px;
+    }
   }
 }
 
index 7744f91500646bb2027672cce184a4474e31fd51..10fa379760f46f6b57c936c6851e2b9e26fad41f 100644 (file)
@@ -1304,6 +1304,12 @@ menu,
   menu menuitem,
   .menu menuitem {
     min-width: 40px; }
+    menu menuitem arrow,
+    .menu menuitem arrow {
+      margin-left: 10px; }
+    menu menuitem arrow:dir(rtl),
+    .menu menuitem arrow:dir(rtl) {
+      margin-right: 10px; }
 
 /***************
  * Popovers   *